﻿#if UNITY_EDITOR && DEBUG_BEHAVIOUR_TREE
#define DEBUG_TREE
#endif
using System.Collections.Generic;
using System.Linq;
#if UNITY_EDITOR
using UnityEditor;
#endif

namespace GameToolkit.BehaviourTree
{
    public enum NodeState : byte
    {
        Inactive,
        Running,
        Success,
        Failed,
    }

    /// <summary>
    /// 行为树父节点
    /// </summary>
    public interface IExecutableParent
    {
        int ChildCount { get; }
        ExecutableEntry GetChild(int index);
    }

    /// <summary>
    /// 行为树运行时对象
    /// </summary>
    public abstract partial class BehaviourTreeObject
    {
        #region internal api (don't rewrite)
#if UNITY_EDITOR
        // 当前绑定的配置数据
        internal string guid;
        internal BehaviourTreePlayer attachedPlayer;
#endif
        Composite mComposite;
        internal virtual void InitializeSelf(CreateBehaviourTreeContext context)
        {
            mComposite = context.composite;
#if UNITY_EDITOR
            guid = mComposite._guid;
            attachedPlayer = context.player;
#endif
        }
        internal virtual void GetRootCallbacks(ICollection<IExecutableRootCallback> callbacks)
        {
            if (this is IExecutableRootCallback rcall)
                callbacks.Add(rcall);
        }
        internal abstract void InvokeCreateRecursive(BehaviourTreePlayer player);
        internal abstract void InvokeDestroyRecursive(BehaviourTreePlayer player);

#if UNITY_EDITOR
        // 替换对象（仅限编辑器运行时属性发生改变需要重新指定对象使用）
        internal virtual void InternalReplace(BehaviourTreeObject other)
        {
            mComposite = other.composite;
            guid = other.guid;
            attachedPlayer = other.attachedPlayer;
        }
#endif
        #endregion
    }

    /// <summary>
    /// 行为树节点
    /// </summary>
    public abstract partial class ExecutableEntry : BehaviourTreeObject
    {

#if UNITY_EDITOR
        static ExecutableEntry sAssert;
        public bool IsAssert
        {
            get { return sAssert == this; }
            set
            {
                if (value)
                    sAssert = this;
                else if (sAssert == this)
                    sAssert = null;
            }
        }
#endif

        NodeState mState;
        ExecutableEntry mParent;
        Decoration[] mDecorators;
        IInterruptionSource mCondition;
        IExecutableEntryCallback[] mEntries;
        //bool mIsOn; // 满足执行条件
        //internal bool IsOn => mIsOn;
        public NodeState State
        {
            get { return mState; }
            internal set
            {
#if DEBUG_TREE
                var stat = mState;
#endif
                mState = value;

#if DEBUG_TREE
                if (stat != mState && attachedPlayer != null)
                {
                    attachedPlayer.ValidateState(this);
                }
#endif
            }
        }
        internal override void InitializeSelf(CreateBehaviourTreeContext context)
        {
            base.InitializeSelf(context);
            mParent = context.parent as ExecutableEntry;
            var decorators = context.decoratorBuffer;
            var entries = context.entryBuffer;

            mDecorators = decorators.Count > 0 ? decorators.ToArray() : null;
            mEntries = entries.Count > 0 ? entries.ToArray() : null;

            var interrupts = context.interruptionBuffer;
            if (interrupts.Count > 1)
            {
                mCondition = ((ExecutableComposite)composite).m_ConditionLogic == ConditionLogic.Or ? new OrLogicInput(interrupts.ToArray()) : new AndLogicInput(interrupts.ToArray());
            }
            else if (interrupts.Count == 1)
            {
                mCondition = interrupts[0];
            }
            else
            {
                mCondition = null;
            }
        }

        internal override void GetRootCallbacks(ICollection<IExecutableRootCallback> callbacks)
        {
            base.GetRootCallbacks(callbacks);
            var len = DecoratorCount;
            for (int i = 0; i < len; i++)
            {
                mDecorators[i].GetRootCallbacks(callbacks);
            }
        }

        internal sealed override void InvokeCreateRecursive(BehaviourTreePlayer player)
        {
            OnCreate(player);
            var len = DecoratorCount;
            for (int i = 0; i < len; i++)
            {
                mDecorators[i].InvokeCreateRecursive(player);
            }
            if (this is IExecutableParent parent)
            {
                len = parent.ChildCount;
                for (int i = 0; i < len; i++)
                {
                    parent.GetChild(i).InvokeCreateRecursive(player);
                }
            }
        }

        internal sealed override void InvokeDestroyRecursive(BehaviourTreePlayer player)
        {
            if (this is IExecutableParent parent)
            {
                var child = parent.ChildCount;
                for (int i = 0; i < child; i++)
                {
                    parent.GetChild(i).InvokeDestroyRecursive(player);
                }
            }
            var decors = DecoratorCount;
            for (int i = 0; i < decors; i++)
            {
                mDecorators[i].InvokeDestroyRecursive(player);
            }
            OnDestroy(player);
        }

        // 更新装饰节点状态
        internal NodeState GetInterruptResult(BehaviourTreePlayer player)
        {
#if DEBUG_TREE
            IsStateObsolute = false;

            if (mCondition is ComplexLogicInput complex)
            {
                var logic = ((ExecutableComposite)composite).m_ConditionLogic;
                if (logic != complex.Logic)
                {
                    var cond = mCondition;
                    if (logic == ConditionLogic.And)
                        mCondition = new AndLogicInput();
                    else
                        mCondition = new OrLogicInput();
                    ((ComplexLogicInput)mCondition).InternalReplace(complex);
                }
            }

#endif
            var isOn = State == NodeState.Running || IsExecutable(player);
            if (isOn)
            {
                NodeState result = mCondition == null ? NodeState.Running : mCondition.GetInterruptResult(player);
#if DEBUG_TREE
                if (mCondition is Decoration decor2)
                    decor2.State = result;
#endif
                return result;
            }
            else
            {
                return NodeState.Failed;
            }
        }

        internal void InvokeInterrupt(BehaviourTreePlayer player, bool successInterruption)
        {
            NodeState stat;
            if (State == NodeState.Running)
            {
                stat = OnInterrupt(player, successInterruption);
                if (stat <= NodeState.Running)
                    stat = successInterruption ? NodeState.Success : NodeState.Failed;
            }
            else
            {
                stat = successInterruption ? NodeState.Success : NodeState.Failed;
            }
            State = stat;
        }

        internal void InvokeOnStart(BehaviourTreePlayer player)
        {
            State = NodeState.Running;
#if DEBUG_TREE
            if (this is IExecutableParent parent)
            {
                var size = parent.ChildCount;
                for (int i = 0; i < size; i++)
                {
                    var child = parent.GetChild(i);
                    if (child != null)
                        child.State = NodeState.Inactive;
                }
            }
#endif
            OnStart(player);
            var len = mEntries == null ? 0 : mEntries.Length;
            for (int i = 0; i < len; i++)
            {
                mEntries[i].OnStart(player);
            }
        }

        internal void InvokeOnStop(BehaviourTreePlayer player)
        {
            var len = mEntries == null ? 0 : mEntries.Length;
            for (int i = 0; i < len; i++)
            {
                mEntries[i].OnStop(player);
            }
            OnStop(player);
        }

    }

}
